How to add a close button to the Ajax Control Toolkit Calendar Extender control

May 9, 2009

In this series of educational articles, I have been explaining how to enhancing the Ajax Control Toolkit Calendar Extender control to support a number of different modes, such as Day, Month, Quarter, Year, Decade. I have also introduced implemented the InitialView property, which allows you to select an initial mode that you want the calendar to display in. These features may be used to reduce the number of clicks required to select a birthdate from 9 to 4, which is a productivity improvement for anyone seriously using the calendar for data entry purposes

These are the articles so far:

How to patch the Ajax Control Toolkit CalendarExtender to add Decade support and InitialView – Part 1 

How to patch the Ajax Control Toolkit Calendar Extender control to show a Quarter view

How to patch the Ajax Control Toolkit Calendar Extender control to show a Day, Month, MonthYearDecade, Quarter, YearDecade and Decade view

The code for the starting point for these modifications is found here:

http://cid-5e237543fffb2891.skydrive.live.com/self.aspx/Public/AjaxControlToolkit-Framework3.5SP1withDecadeYearQuarterMonthDayandInitialView.zip

Unzip this code and place it in your projects folder. All code here is supplied under the Microsoft Public Licence, found here: http://ajaxcontroltoolkit.codeplex.com/license

The code:

To start with, you’ll need a Close Button. The close button is 15 pixels by 15 pixels. I have created one based on the Internet Explorer X button used to stop web pages from executing. You can download my image by right clicking this image and saving it onto your local drive:

Close Button for Ajax Control Toolkit calendar extender control

This close button image is called close-button.gif (note that it’s a dash, not an underscore).

Copy this image into the Calendar folder in the Ajax Control Toolkit, and set it’s Build Action to Embedded Resource. This is important, as without it, the image is not contained within the Ajax Control Toolkit dll.

Adding the close button image

Adding the close button image

Next, you need to tell the compiler about the image by making it a Web Resource. This is done by adding an entry at the top of the CalendarExtender.cs file, as follows. Note that I am using S5/E5 to tag changes.

Original code:


#region [ Resources ]

[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.CalendarBehavior.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.Calendar.css", "text/css", PerformSubstitution = true)]
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.arrow-left.gif", "image/gif")]
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.arrow-right.gif", "image/gif")]
#endregion

Modified code:


#region [ Resources ]

[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.CalendarBehavior.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.Calendar.css", "text/css", PerformSubstitution = true)]
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.arrow-left.gif", "image/gif")]
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.arrow-right.gif", "image/gif")]
//S5
[assembly: System.Web.UI.WebResource("AjaxControlToolkit.Calendar.close-button.gif", "image/gif")]
//E5
endregion

Next, we want to add a property to the Calendar Extender to allow us to turn the close button display on or off – not everyone wants a close button on their calendar. Most people are probably content with clicking off the calendar. I will add a property called ShowCloseButton to the extender control. In the CalendarExtender.cs file, I copy the EnabledOnClient property and paste it to the location next to it. Then I rename the variables to be consistent with the property I want.

Code added under EnabledOnClient property:


//S5
[DefaultValue(false)]
[ExtenderControlProperty]
[ClientPropertyName("showCloseButton")]
public virtual bool ShowCloseButton
{
    get { return GetPropertyValue("ShowCloseButton", false); }
    set { SetPropertyValue("ShowCloseButton", value); }
}
//E5

The ClientPropertyName attribute contains the client-side javascript variable name. So next we go into the CalendarBehavior.js file and add in a couple of javascript variables. The first is the showCloseButton variable, shown above, and the second is the placeholder variable for the close button html content that will be created when the close button is required to be displayed. This code goes in the declarations section of the CalendarBehavior.js file. I put mine just below the declaration for this._nextArrow = null;


/*S5*/
this._showCloseButton = false;
this._closeButton = null;
/*E5*/

Add the getter and setter next. I put mine just below the set_enabled function block.


//S5
get_showCloseButton: function() {
    /// <value type="Boolean">
    /// Whether this behavior is available for the current element
    /// </value>

    return this._showCloseButton;
},
set_showCloseButton: function(value) {
    if (this._showCloseButton != value) {
        this._showCloseButton = value;
        this.invalidate();
        this.raisePropertyChanged("showCloseButton");
    }
},
//E5

The function that builds the calendar in the first place is called _buildHeader. This is where we need to add code to test if the close button is supposed to display, create the div that contains the image, and attach the event handlers. This is also where the stylesheet class is attached to the div. The image itself is referenced from that stylesheet class, called ajax__calendar_close.


/*S5 - because the close button is floated right, it needs to go before the nextArrow div as that is
also floated right, and right floating reverses the order of display*/
if (this._showCloseButton) {
    var closeButtonWrapper = $common.createElementFromTemplate({ nodeName: "div" }, this._header);
    this._closeButton = $common.createElementFromTemplate({
        nodeName: "div",
        properties: {
            id: id + "_closeButton",
            mode: "close"
        },
        events: this._cell$delegates,
        cssClasses: ["ajax__calendar_close"]
    }, closeButtonWrapper);
}
/*E5*/

 

 Note in that code the reference to the mode property. That is the string that gets passed into the _cell_onclick event handler. So on clicking the close button image, we want the calendar to execute the same code that is executed when the Escape button is clicked. So I had a look in the _button_onkeypress function and saw the code that is being executed when the Escape key is pressed. I will copy that code into the _cell_onclick function, and add a case for the ‘close’ mode, as follows:

Original code:


case "prev":
case "next":
    this._switchMonth(target.date);
    break;

Modified code:


case "prev":
case "next":
    this._switchMonth(target.date);
    break;
/*S5*/
case "close":
    e.stopPropagation();
    e.preventDefault();
    this.hide();
    break;
/*E5*/

Finally, you need to dispose of the close button content correctly. In the dispose function, add the following modifications:

Original code:

if (this._nextArrow) {
    $common.removeHandlers(this._nextArrow, this._cell$delegates);
    this._nextArrow = null;
}

Modified code:

if (this._nextArrow) {
    $common.removeHandlers(this._nextArrow, this._cell$delegates);
    this._nextArrow = null;
}
/*S5*/
if (this._showCloseButton && this._closeButton) {
    $common.removeHandlers(this._closeButton, this._cell$delegates);
    this._closeButton = null;
}
/*E5*/

Finally, you need to add the calendar extender css class for the close button. Open the Calendar.css file, and just below the entry for .ajax__calendar_next, add the following line:


/*S5*/
.ajax__calendar_close {cursor:pointer;width:15px;height:15px;float:right;background-repeat:no-repeat;background-position:50% 50%;background-image:url(<%=WebResource("AjaxControlToolkit.Calendar.close-button.gif")%>);}
/*E5*/

 

Run it up, add a calendar extender, set it’s ShowCloseButton property to true, and this is what you see:

Calendar Close Button Image

Calendar Close Button Image

Note that I have deliberatelychosen a non-intrusive close button, the same size as the prev and next buttons. The close button just needs to be there – it doesn’t need to out-weigh the other elements on the calendar. I used to have a bright red button, but that is so 20th century.

If you would like to see if you’ve got the code right, I have a completed version to compare with here:

AjaxControlToolkit3.5SP1withModesAndCloseButton.zip